﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Text;
using FinPlusInterfaces;

namespace FinPlusConnMessage
{
    public sealed class Transport : IDisposable, ITransport
    {
        public IListener Listener { get; set; }
        
        private readonly Connection _connListen, _connSend;
        private readonly ConcurrentDictionary<string, IMessage> _cacheMessages;
        private readonly ConcurrentBag<string> _cacheTopics;
        private Byte[] _buffer = null;

        //construct
        public Transport(string address, int port) : this(address, port, null) { }

        public Transport(string address, int port, IPAddress endpoint)
        {
            _cacheMessages = new ConcurrentDictionary<string, IMessage>();
            _cacheTopics = new ConcurrentBag<string>();
            _connSend = new Connection(address, port);
            _connListen = new Connection(address, port, IPAddress.Any);
            Listener = new Listener(_connListen, _cacheTopics);
            Listener.MessageResend += Message_Resend;
        }

        //public
        public string Publish(IMessage message)
        {
            try
            {
                _buffer = Encoding.Unicode.GetBytes(message.ToString());
                _connSend.Client.Send(_buffer, _buffer.Length, _connSend.Endpoint);

                if (!message.RequestResendCache)//dont want to locally cache resend request
                {
                    _cacheMessages[message.Topic] = message;
                    string topic;
                    if (!_cacheTopics.TryPeek(out topic)) 
                        _cacheTopics.Add(message.Topic);
                }

                return "Published";
            }
            catch (Exception e)
            {
                return e.ToString();
            }
        }

        public void Listen(string topic, bool requestCache = false)
        {
            Listener.Listen(topic); //single listener per transport;
            if (requestCache) 
                Publish(new Message(topic +"|String|true|"));
        }
        
        public void Dispose()
        {
            if(Listener!=null) 
                Listener.Dispose();
            
            if(_connSend !=null)
                _connSend.Dispose();
            
            if(_connListen != null)
                _connListen.Dispose();
        }

        //events
        private void Message_Resend(object s, EventArgs a)
        {
            var res = (MessageEventArgs)a;
            IMessage val;
            if (_cacheMessages.TryGetValue(res.Message.Topic, out val))
                Publish(val);
        }
    }
}
